package mcjunkin;
import java.util.*;
import java.io.*;
import java.math.*;
import java.security.*;

/**
	This encapsulates a file in the system.
*/

public class MatchFile extends Match implements Comparable{
	
	//the data about this file we store for convenience
	private long length;
	private String hash;

	/** Constructs a matchfile on top of the underlying file. */
	public MatchFile(File f, MatchFolder p) throws IOException, 
		NoSuchAlgorithmException{
		super(f,p);
		length = f.length();
		hash = null;
	}

	/** Retreives the length */
	public long getLength(){
		return length;
	}

	/** Retreives true or false depending on whether or not the
		hash has been generated. */		
	public boolean hasHash(){
		return hash != null;
	}

	/** Retreives the hash */
	public String getHash() throws IOException, NoSuchAlgorithmException{
		if(hash == null){
			hash = getMD5Checksum(file);
			//notify parent the hash is now available
			if(parent != null) parent.notifyChildGeneratedHash(this);
		}
		return hash;
	}

	/** Checks to see if two files or equal. First compares the length,
		then the hash if the length matches. */
	public boolean equals(Object o){
		return compareTo(o) == 0;
	}

	/** Compares two match files. First compares the length,
		then the hash if the length matches. Returns 1 for non matchfiles,
		alphanumeric comparison of lengths, then hashes for matchfiles. */
	public int compareTo(Object o){

		//return 1 if the other object isnt of correct type
		if(!(o instanceof MatchFile)) return 1;

		//compare lengths
		Long myLength = new Long(getLength());
		Long theirLength = new Long(((MatchFile)o).getLength());
		int c=myLength.compareTo(theirLength);
		if(c != 0) return c;
		
		//compare hashes
		try{
			String myHash = getHash();
			String theirHash = ((MatchFile)o).getHash();
			return myHash.compareTo(theirHash);
		}
		catch(IOException iex){return 10;}
		catch(NoSuchAlgorithmException nsx){return 10;}	
	}

	//pair of methods for getting MD5
	//http://stackoverflow.com/questions/304268/getting-a-
	//   files-md5-checksum-in-java
	private static String getMD5Checksum(File file) throws IOException,
		NoSuchAlgorithmException{
		byte[] b = createChecksum(file);
		String result = "";
		for (int i=0; i < b.length; i++) {
			result += Integer.toString( ( b[i] & 0xff ) + 0x100, 16).substring(1);
		}
		return result;
	}
	private static byte[] createChecksum(File file) throws IOException,
		NoSuchAlgorithmException{
		InputStream fis =  new FileInputStream(file);

		byte[] buffer = new byte[1024];
		MessageDigest complete = MessageDigest.getInstance("MD5");
		int numRead;

		do {
			numRead = fis.read(buffer);
			if (numRead > 0) {
				complete.update(buffer, 0, numRead);
			}
		} while (numRead != -1);

		fis.close();
		return complete.digest();
	}

}
